#!/usr/bin/env python3
#
# generate_docker_compose.py
#
# Generate configuration from Jinja template.
#
# usage: python3 ./script/generate_docker_compose.py
# (call only from root repository)
#
# Generate configuration with .env.values:
# - from ./build-template/**/*.template (Jinja template) to ./build/**/*

import configparser
import os
import sys
import re
import shutil

import glob2
import jinja2

def read_context(file_path):
    """Read a configuration file (bash compatible with source).

    Parameters
    ----------
    file_path : string
        Configuration file (bash compatible with source).

    Returns
    -------
    dict
        Configuration under the shape of dictionnary (key, value).
    """
    with open(file_path, "r") as desc:
        _buffer = "[section]\n"
        _buffer += desc.read()
    config = configparser.RawConfigParser()
    # preserve case
    config.optionxform = str
    config.read_string(_buffer)
    return dict(config.items("section"))

def render(template_path, context, generate_file=True, begin_comment="#", end_comment=''):
    """From a template Jinja (with extension .template) and a context
    generate a configuration and create a file (without extension .template)
    if precised. Add a header to this configuration to mark the file as
    generated.

    Parameters
    ----------
    template_path : string
        Path file to Jinja template (with extension .template).

    context : dict
       (key, value) parameters to feed to JinJa template.

    generate_file : bool (optional, by default True)
        If true, persist generated configuration to a file in same directory
        than Jinja template (without extension .template).

    begin_comment : string (optional, by default #)
        begin token for inline comment in generated configuration

    end_comment : string (optional, by default empty)
        end token for inline comment in generated configuration

    Returns
    -------
    string
        Content of generated configuration file
    """
    path, filename = os.path.split(template_path)
    content = jinja2.Environment(
        loader=jinja2.FileSystemLoader(path)
    ).get_template(filename).render(context)
    content = "{} {}{}\n{} {}{}\n\n{}".format(
        begin_comment,
        "Generated from Jinja template",
        end_comment,
        begin_comment,
        "DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN",
        end_comment,
        content)
    if generate_file:
        # delete .template extension
        conf_filename, _ = os.path.splitext(filename)
        conf_path = os.path.join(path, conf_filename)
        with open(conf_path, "w") as desc:
            desc.write(content)
    return content

if __name__ == "__main__":
    os_container = os.getenv('OS_CONTAINER')
    realm = os.getenv('REALM_KRB5')
    build_id = f"{os_container}-{realm}".lower()
    build_name = f"build-{build_id}"
    print(f"=== generate docker compose configuration {build_id} ===")
    if not os.path.isfile(".env.values"):
        print("ERROR: .env.values doesn't exist!", file=sys.stderr)
        sys.exit(1)
    context = read_context(".env.values")
    print(f"=== copy template directory to ./build-template to ./{build_name} ===")
    if os.path.exists(f"./{build_name}"):
        print(f"=== remove existing ./{build_name} ====")
        shutil.rmtree(f"./{build_name}")
    shutil.copytree(f"./build-template/krb5-{os_container}", f"./{build_name}/krb5-{os_container}")    
    shutil.copytree("./build-template/nodes", f"./{build_name}/nodes") 
    shutil.copytree("./build-template/services", f"./{build_name}/services")
    shutil.copyfile("./build-template/docker-compose.yml.template", f"./{build_name}/docker-compose.yml.template")
    print("=== generate template configuration for ./build ===")
    for template_path in glob2.glob(f"./{build_name}/**/*.template", recursive=True):
        if not os.path.isfile(template_path):
            continue
        print(f"render {template_path}")
        begin_comment = '#'
        end_comment = ''
        basename = os.path.basename(template_path)
        basename = re.sub('.template$', '', basename)
        if basename == 'supervisord.conf':
            begin_comment = ';'
        elif basename.endswith('.html'):
            begin_comment = '<!--'
            end_comment = ' -->'
        render(template_path, context, begin_comment=begin_comment, end_comment=end_comment)
        print(f"remove {template_path}")
        os.remove(template_path)
    print("...OK")

